package com.workspace.chb_website.service;

import com.workspace.chb_website.bean.MetaBean;
import com.workspace.chb_website.bean.RespBean;
import com.workspace.chb_website.bean.User;
import com.workspace.chb_website.mapper.WorkLogMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

@Service
public class WorkLogService {

    private final WorkLogMapper workLogMapper;

    @Autowired
    public WorkLogService(WorkLogMapper workLogMapper) {
        this.workLogMapper = workLogMapper;
    }

    public int isHasLog(String id) {
        return workLogMapper.isHasLog(id);
    }

    public List<String> getAllProject() {
        return workLogMapper.getAllProject();
    }

    public List<String> findProject(String word) {
        return workLogMapper.findProject(word);
    }

    public List<Map<String, String>> getWorkDate(String name) {
        return workLogMapper.getWorkDate(name);
    }

    public List<Map<String, String>> getAllWorkLog(User user, String month) {
        List<Map<String, String>> re = workLogMapper.getAllWorkLog(user.getId(), month);
        for (Map<String, String> r : re) {
            r.put("NAME", user.getRealname());
        }
        return re;
    }

    /**
     * 查找某人某月工作记录
     *
     * @param name  姓名
     * @param month 月份（格式：yyyy-MM）
     * @return 用map储存的一条记录的list集合，map中两个key：projectName和workDay，其中workDay是个元素为int的list，代表这个项目在这个月哪些天
     */
    public List<Map<Object, Object>> getWorkLog(String name, String month) {
        //数据库中原始数据
        List<Map<String, String>> logs = workLogMapper.getWorkLog(name, month);
        //定义返回数据re
        List<Map<Object, Object>> re = new ArrayList<>();
        for (Map<String, String> log : logs) {
            //定义re的元素el
            Map<Object, Object> el = new HashMap<>();
            //去re中查找是否已经存在该项目名，若存在返回索引，不存在返回-1
            int index = -1;
            for (int i = 0; i < re.size(); i++) {
                if (Objects.equals(re.get(i).get("projectName").toString(), log.get("PROJECTNAME"))) {
                    index = i;
                    break;
                }
            }
            //定义el的value变量，是一个int数组
            List<Integer> days = new ArrayList<>();
            int start = Integer.parseInt(log.get("STARTDAY"));
            int end = Integer.parseInt(log.get("ENDDAY"));
            for (int i = start; i <= end; i++) {
                if (index == -1)
                    days.add(i);
                else
                    //若返回索引不为-1则向原有的数组中继续添加数字
                    ((List<Integer>) re.get(index).get("workDay")).add(i);
            }
            if (index == -1) {
                //新加入元素el
                el.put("projectName", log.get("PROJECTNAME"));
                el.put("workDay", days);
                re.add(el);
            }
        }
        //在re的最后添加此人该月所有不重复的项目名称
        Map<Object, Object> el = new HashMap<>();
        el.put("distinctProject", workLogMapper.getProject(name, month));
        re.add(el);
        return re;
    }

    /**
     * 插入工作记录执行函数
     *
     * @param user      当前用户
     * @param project   项目名字
     * @param startDate 开始日期
     * @param endDate   结束日期
     * @return RespBean
     * @throws ParseException sdf.parse(startDate)中startDate不是yyyy-MM-dd格式
     */
    public RespBean addWorkLog(User user, String project, String startDate, String endDate) throws ParseException {
        //判断起止的月份是否是同一个月，不同的月需要分别插入
        if (getMonthGap(startDate, endDate) == 1) {
            Map<String, String> re = splitDate(startDate);
            //插入起始日期到这个月最后一天的记录
            RespBean status_1 = performAdd(project, startDate, re.get("end_current"), user.getId());
            //插入下个月的第一天到结束日期的记录
            RespBean status_2 = performAdd(project, re.get("start_next"), endDate, user.getId());

            //如果其中一个失败，则回滚
            if (status_1.getMeta().getStatus() == 400 && status_2.getMeta().getStatus() == 200) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return new RespBean("", status_1.getMeta());
            }
            if (status_2.getMeta().getStatus() == 400 && status_1.getMeta().getStatus() == 200) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return new RespBean("", status_2.getMeta());
            }
            if (status_1.getMeta().getStatus() == 400 && status_2.getMeta().getStatus() == 400) {
                return new RespBean("", new MetaBean(400, "插入失败"));
            }
            return new RespBean("", new MetaBean(200, "插入成功"));
        } else if (getMonthGap(startDate, endDate) == 0)
            //在同一个月中就直接调用
            return performAdd(project, startDate, endDate, user.getId());
        return new RespBean("", new MetaBean(400, "插入失败,时间跨度请不要超过两个月"));
    }

    /**
     * 删除执行函数
     *
     * @param user      当前用户
     * @param startDate 开始日期
     * @param endDate   结束日期
     * @return RespBean
     * @throws ParseException sdf.parse(startDate)中startDate不是yyyy-MM-dd格式
     */
    public RespBean deleteWorkLog(User user, String startDate, String endDate) throws ParseException {
        //判断起止的月份是否是同一个月，不同的月需要分别删除
        if (getMonthGap(startDate, endDate) == 1) {
            Map<String, String> re = splitDate(startDate);
            int sign_1 = workLogMapper.deleteWorkLog(user.getId(), startDate, re.get("end_current"));
            int sign_2 = workLogMapper.deleteWorkLog(user.getId(), re.get("start_next"), endDate);
            //如果其中一个失败，则回滚
            if (sign_1 != 1 || sign_2 != 1) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return new RespBean("", new MetaBean(400, "删除失败,请核对时间及姓名"));
            } else
                return new RespBean("", new MetaBean(200, "删除成功"));
        } else if (getMonthGap(startDate, endDate) == 0) {
            //在同一个月中就直接调用
            if (workLogMapper.deleteWorkLog(user.getId(), startDate, endDate) == 1)
                return new RespBean("", new MetaBean(200, "删除成功"));
            else
                return new RespBean("", new MetaBean(400, "删除失败,请核对时间及姓名"));
        }
        return new RespBean("", new MetaBean(400, "删除失败,时间跨度请不要超过两个月"));
    }

    /**
     * 获得输入日期当月的最后一天和下个月第一天
     *
     * @param startDate 开始的日期
     * @return Map中有两个key：end_current（输入日期当月最后一天）和start_next（下个月的第一天）
     * @throws ParseException sdf.parse(startDate)中startDate不是yyyy-MM-dd格式
     */
    private Map<String, String> splitDate(String startDate) throws ParseException {
        Map<String, String> re = new HashMap<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Calendar cal = Calendar.getInstance();
        cal.setTime(sdf.parse(startDate));
        //修改天为这个月最后一天
        cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
        String end_current = sdf.format(cal.getTime());
        re.put("end_current", end_current);
        //天+1就是下个月的第一天
        cal.add(Calendar.DAY_OF_MONTH, 1);
        String start_next = sdf.format(cal.getTime());
        re.put("start_next", start_next);
        return re;
    }

    /**
     * 判断两个日期之间相差几个月
     *
     * @param startDate 开始日期
     * @param endDate   结束日期
     * @return 整形int表示相差的月份数
     * @throws ParseException sdf.parse(startDate)中startDate不是yyyy-MM-dd格式
     */
    private int getMonthGap(String startDate, String endDate) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Calendar cal = Calendar.getInstance();

        cal.setTime(sdf.parse(endDate));
        cal.set(Calendar.DAY_OF_MONTH, cal.getActualMinimum(Calendar.DAY_OF_MONTH));
        String a = sdf.format(cal.getTime());

        cal.setTime(sdf.parse(startDate));
        cal.set(Calendar.DAY_OF_MONTH, cal.getActualMinimum(Calendar.DAY_OF_MONTH));
        for (int i = 0; i < 12; ++i) {
            String b = sdf.format(cal.getTime());
            if (Objects.equals(a, b)) {
                return i;
            }
            cal.add(Calendar.MONTH, 1);
        }
        return -1;
    }

    /**
     * 日期拆分完之后的插入执行函数
     *
     * @param pro   项目名字
     * @param start 开始日期
     * @param end   结束日期
     * @param id    用户id
     * @return RespBean
     */
    private RespBean performAdd(String pro, String start, String end, String id) {
        //判断输入的项目名是否已存在
        String project_id = workLogMapper.getIdByProject(pro);
        if (project_id == null) {
            //若不存在则向project表中插入新纪录，然后再次查询id
            workLogMapper.addProject(pro);
            project_id = workLogMapper.getIdByProject(pro);
        }
        int proid = Integer.parseInt(project_id);
        //若起止日期和记录中完全一致，则进行项目名称的更新
        if (workLogMapper.updateWorkLog(id, start, end, proid) == 1)
            return new RespBean("", new MetaBean(200, "更新成功"));
        //核对日期是否和已存在记录的日期相互重叠
        if (workLogMapper.checkDate(id, start, end) != 0)
            return new RespBean("", new MetaBean(400, "时间冲突"));
        //调用插入语句
        if (workLogMapper.addWorkLog(id, start, end, proid) == 1)
            return new RespBean("", new MetaBean(200, "插入成功"));
        else
            return new RespBean("", new MetaBean(400, "插入失败"));
    }
}
